#include <winsock.mqh>
#import "user32.dll"
bool GetAsyncKeyState(int Key);
#import
 
#define DEFAULT_PORT 2007
#property show_inputs
extern string protocol="TCP";
extern int port=DEFAULT_PORT;
extern string ip_address="";
extern int maxloop=-1;

void Usage() {
    Print("\t- The defaults are TCP, 2007 and INADDR_ANY.");
    Print("\t- Hit ESC to terminate server script...");
    Print("\t- maxloop is the number of loops to execute 0=endless.");
    Print("\t  decimal notation) to bind to. But it is not useful here...");
    Print("\t- ip_address if blank means any");
    Print("\t- port is the port to listen on");
    Print("Where:\n\t- protocol is one of TCP or UDP");
    Print("Usage: protocol port ip_address");
    WSACleanup();
}

int  start() {
    int Buffer[32];
    int retval;
    int fromlen[1];
    int i, loopcount=0;
    int socket_type = SOCK_STREAM;
    int  local[sockaddr_in], from[sockaddr_in];
    int wsaData[WSADATA];
    int listen_socket, msgsock;
    
    if (protocol=="TCP")
      socket_type = SOCK_STREAM; 
    else if (protocol=="UDP")
      socket_type = SOCK_DGRAM;
    else {
      Usage();
      return(-1);
    }    
    if (port==0) {
      Usage();
      return(-1);
    }    
 
    retval = WSAStartup(0x202, wsaData);
    if (retval != 0) {
        Print("Server: WSAStartup() failed with error "+ retval);
        WSACleanup();
        return(-1);
    } else
       Print("Server: WSAStartup() is OK.");
 
    int2struct(local,sin_family,AF_INET);
    Print(AF_INET+" family:"+local[0]+" "+local[1]+" "+local[2]+" "+local[3]+" f:"+sin_family);
    if (ip_address=="") 
      int2struct(local,sin_addr,INADDR_ANY); 
    else  
      int2struct(local,sin_addr,inet_addr(ip_address)); 
    Print(inet_addr(ip_address)+" addr:"+local[0]+" "+local[1]+" "+local[2]+" "+local[3]+" f:"+sin_addr);
    int2struct(local,sin_port,htons(port));
    Print(htons(port)+" port:"+local[0]+" "+local[1]+" "+local[2]+" "+local[3]+" f:"+sin_port);
    listen_socket = socket(AF_INET, socket_type,0);
 
    if (listen_socket == INVALID_SOCKET){
        Print("Server: socket() failed with error "+WSAGetLastError());
        WSACleanup();
        return(-1);
    } else
       Print("Server: socket() is OK.");
    Print("sin_family:"+struct2int(local,sin_family)+" sin_port:"+struct2int(local,sin_port)+" sin_addr:"+struct2int(local,sin_addr));
    if (bind(listen_socket, local, ArraySize(local)<<2) == SOCKET_ERROR) {
        Print("Server: bind() failed with error "+WSAGetLastError());
        WSACleanup();
        return(-1);
    } else
        Print("Server: bind() is OK");
 
    if (socket_type != SOCK_DGRAM) {
        if (listen(listen_socket,5) == SOCKET_ERROR) {
            Print("Server: listen() failed with error "+ WSAGetLastError());
            WSACleanup();
            return(-1);
        } else
            Print("Server: listen() is OK.");
    }
    Print("Server: listening and waiting connection port:"+port+", protocol:"+protocol);
    while(!IsStopped()) {
       fromlen[0] =ArraySize(from)<<2;
       if (socket_type != SOCK_DGRAM) {
          msgsock = accept(listen_socket, from, fromlen);
          if (msgsock == INVALID_SOCKET) {
             Print("Server: accept() error "+ WSAGetLastError());
             WSACleanup();
             return(-1);
          } else
            Print("Server: accept() is OK.\n");
          Print("Server: accepted connection from "+inet_ntoa(struct2int(from,sin_addr))+", port "+ htons(struct2int(from,sin_port))) ;
       } else 
          msgsock = listen_socket;
       if (socket_type != SOCK_DGRAM)
          retval = recv(msgsock, Buffer, ArraySize(Buffer)<<2, 0);
       else {
          retval = recvfrom(msgsock,Buffer, ArraySize(Buffer)<<2, 0, from, fromlen);
          Print("Server: Received datagram from "+ inet_ntoa(struct2int(from,sin_addr)));
       }
       if (retval == SOCKET_ERROR) {
          Print("Server: recv() failed: error "+ WSAGetLastError());
          closesocket(msgsock);
          continue;
       } else
          Print("Server: recv() is OK.");
       if (retval == 0) {
          Print("Server: Client closed connection.\n");
          closesocket(msgsock);
          continue;
       }
       Print("Server: Received "+retval+" bytes, data \""+struct2str(Buffer,ArraySize(Buffer)<<18)+"\" from client");
       Print("Server: Echoing the same data back to client...");
       if (socket_type != SOCK_DGRAM)
          retval = send(msgsock, Buffer, ArraySize(Buffer)<<2, 0);
       else
          retval = sendto(msgsock, Buffer, ArraySize(Buffer)<<2, 0, from, fromlen[0]);
       if (retval == SOCKET_ERROR)
          Print("Server: send() failed: error "+WSAGetLastError());
       else
          Print("Server: send() is OK.");
        Sleep(1000);
        loopcount++;
        if (maxloop<0) break;
        if ((loopcount >= maxloop) && (maxloop >0))
          break;
       if(GetAsyncKeyState(27)) break;
       if (socket_type != SOCK_DGRAM) {
          Print("Server: waiting for connections, try running the client");
          Print("Server: script from the same computer or other computer...");
          closesocket(msgsock);
        } 
   }
   return(0);
}

int deinit() {
  WSACleanup();
  Comment("");

}